package drds.plus.datanode.api;

import drds.plus.common.Constants;
import drds.plus.common.lifecycle.AbstractLifecycle;
import drds.plus.common.lifecycle.Lifecycle;
import drds.plus.datanode.configuration.DataNodeConfigurationManager;
import drds.plus.datanode.fetcher.DataSourceFetcher;
import drds.plus.datanode.select.Selector;
import drds.plus.datasource.api.DataSource;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;

import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.Map;

@Slf4j
public class DatasourceManager extends AbstractLifecycle implements Lifecycle {

    @Setter
    @Getter
    private DataNodeConfigurationManager dataNodeConfigurationManager;

    @Setter
    @Getter
    private String dataSourceIdAndWeightStringArrayString;
    @Setter
    @Getter
    private DataSourceFetcher dataSourceFetcher;
    @Setter
    @Getter
    private String applicationId;
    @Setter
    @Getter
    private String dataNodeId;
    @Setter
    @Getter
    private int retryingTimes = 3; // 默认读写失败时重试3次
    @Setter
    @Getter
    private long configReceiveTimeout = Constants.DIAMOND_GET_DATA_TIMEOUT; // 取配置信息的默认超时时间为30秒
    // 当运行期间主备发生切换时是否需要查找第一个可写的库
    @Setter
    @Getter
    private boolean autoSelectWriteDataSource = false;


    public DatasourceManager() {
    }

    public DatasourceManager(String applicationId, String dataNodeId) {
        this.dataNodeId = dataNodeId;
        this.applicationId = applicationId;
    }


    /**
     * 基于dbGroupKey、appName来初始化多个TAtomDataSource
     */
    public void doInit() {
        dataNodeConfigurationManager = new DataNodeConfigurationManager(this);
        dataNodeConfigurationManager.init();
    }


    // 包访问级别，调用者不能缓存，否则会失去动态性
    Selector getSelector(boolean isRead) {
        return dataNodeConfigurationManager.getSelector(isRead, this.autoSelectWriteDataSource);
    }


    // 在ConfigManager中我们将配置信息最终封装为读写DBSelector，要得到从dbKey到DataSource的映射，将DBSelector中的信息方向输出。
    public Map<String, DataSource> getDataSourceIdToDataSourceMap() {
        Map<String, DataSource> dataSourceIdToDataSourceMap = new LinkedHashMap<String, DataSource>();
        dataSourceIdToDataSourceMap.putAll(this.getSelector(true).getDataSourceIdToDataSourceHolderMap());
        dataSourceIdToDataSourceMap.putAll(this.getSelector(false).getDataSourceIdToDataSourceHolderMap());
        return dataSourceIdToDataSourceMap;
    }

    public Connection getConnection() throws SQLException {
        return new Connection(this);
    }


    /**
     * 销毁数据源，慎用
     */
    public void destroyDataSource() throws Exception {
        destroy();
    }

    protected void doDestroy() {

        if (dataNodeConfigurationManager != null) {
            dataNodeConfigurationManager.destroyDataSource();
        }
    }


    public Logger log() {
        return log;
    }
}
